﻿-- Author      : Kurapica

--------------------------
-- DropDownList	        --
--------------------------
--[[
    
--]]
do
	-- Check Version
	local version = 1

	if not IGAS:RegisterFile("IGAS.GUI.Widget.DropDownList", version) then
		return
	end

	local getmetatable = getmetatable
	local pairs = pairs
	local ipairs = ipairs
	local type = type
	local error = error
	local CreateFrame = IGAS.GUI.CreateFrame

	local _GUI = IGAS.GUI
	local _Widget = IGAS.GUI.Widget
	local _BaseFunc = IGAS.GUI.Base.Func
	local _PropertyType = IGAS.GUI.Base.PropertyType
    
    ------------------------------------------------------
	------------------- DropDownMenuButton----------------
	------------------------------------------------------
    local DropDownMenuButton
    local itemHeight = 16
    
    do
        local _WidgetName = "DropDownMenuButton"
        local _Base = "Button"
        
        -- Scripts
        --[[
        local function OpenColorPicker(self)
            ColorPickerFrame.func = info.swatchFunc
            ColorPickerFrame.hasOpacity = info.hasOpacity
            ColorPickerFrame.opacityFunc = info.opacityFunc
            ColorPickerFrame.opacity = info.opacity
            ColorPickerFrame.previousValues = {r = info.r, g = info.g, b = info.b, opacity = info.opacity}
            ColorPickerFrame.cancelFunc = info.cancelFunc
            ColorPickerFrame.extraInfo = info.extraInfo
            -- This must come last, since it triggers a call to ColorPickerFrame.func()
            ColorPickerFrame:SetColorRGB(info.r, info.g, info.b)
            ShowUIPanel(ColorPickerFrame)
        end
        
        --- colorBack
        local function colorBack_OnClick(self)
            self.Parent:Fire("OnClick")
			OpenColorPicker(self:GetParent())
        end
        
        local function colorBack_OnEnter(self)
            self.Parent.Parent:CloseDropDownMenus()
            self:GetChild("Bg"):SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
			self.Parent.Parent:Fire("OnEnter")
        end
        
        local function colorBack_OnLeave(self)
            self:GetChild("Bg"):SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
			self.Parent.Parent:Fire("OnLeave")
        end
        --]]
        local function hideDropList(self)
            if self.__Childs and type(self.__Childs) == "table" then
                for i,v in pairs(self.__Childs) do
                    if type(v) == "table" and v["IsObjectType"] and v:IsObjectType(DropDownMenuButton) then
                        if v.__DropDownList then
                            hideDropList(v.__DropDownList)
                            v.__DropDownList.Visible = false
                        end
                    end
                end
            end
            self.Visible = false
        end
    
        local function hideDropDownList(self)
            if self.__DropDownList then
                hideDropList(self.__DropDownList)
            end
        end
        
        local function showDropDownList(self)
            local offsetx, offsety, menu
            
            -- Hide other sub dropdownlist
            if self.Parent.__Childs and type(self.Parent.__Childs) == "table" then
                for i,v in pairs(self.Parent.__Childs) do
                    if type(v) == "table" then
                        hideDropDownList(v)
                    end
                end
            end
            
            -- Show self's dropdownlist
            menu = self.__DropDownList
            
            if menu then
                menu.Visible = true
                
                -- Offset-X
                if self.Parent:GetRight() + menu.Width > GetScreenWidth() then
                    offsetx = - (self.Parent.Width + menu.Width)
                else
                    offsetx = 0
                end
                -- Offset-Y
                if self:GetTop() < menu.Height then
                    offsety = menu.Height - self:GetTop()
                else
                    offsety = 0
                end
                menu:SetPoint("TOPLEFT", self, "TOPRIGHT", offsetx, offsety)
            end
        end
        
        local function toggleDropDownList(self)
            if self.__DropDownList then
                if self.__DropDownList.Visible then
                    hideDropDownList(self)
                else
                    showDropDownList(self)
                end
            end
        end
        
        --- expandArrow
        local function expandArrow_OnClick(self)
            toggleDropDownList(self.Parent)
        end
        
        local function expandArrow_OnEnter(self)
            showDropDownList(self.Parent)
			self.Parent.Parent:Fire("OnEnter")
        end
        
        local function expandArrow_OnLeave(self)
            self.Parent.Parent:Fire("OnLeave")
        end
        
        -- Item        
        local function item_OnEnter(self)
            showDropDownList(self)
            self:GetChild("HighLight"):Show()
            self.Parent:Fire("OnEnter")
        end
        
        local function item_OnLeave(self)
            self:GetChild("HighLight"):Hide()
            self.Parent:Fire("OnLeave")
        end
        
        local function updateWidth(self)
            local maxW = 0
            
            if self.__Childs and type(self.__Childs) == "table" then
                for i,v in pairs(self.__Childs) do
                    if type(v) == "table" and v["IsObjectType"] and v:IsObjectType(DropDownMenuButton) then
                        if v:GetChild("Text").Width > maxW then
                            maxW = v:GetChild("Text").Width
                        end
                    end
                end
                
                maxW = maxW + 40
                
                self.Width = maxW
            end
        end
        
        -- OnClick Script
        local function OnClick(self, ...)            
            -- if this is checkButton
            if self.__IsCheckButton then
                if self.Parent.MultiSelect then
                    self.Checked = not self.Checked
                    return true
                else
                    if self.Checked then
                        -- No need to action
                        hideDropList(self.Parent)
                        return true
                    end
                    self.Checked = true
                    for i, v in pairs(self.Parent.__Childs) do
                        if type(v) == "table" and v["IsObjectType"] and v:IsObjectType(DropDownMenuButton) and v.__IsCheckButton and v ~= self and v.Checked then
                            v.Checked = false
                        end
                    end
                    hideDropList(self.Parent)
                end
                return
            end
            
            local root = self.Parent
                        
            while root.__MenuBase do
                root = root.__MenuBase
            end
            
            hideDropList(root)
		end
        
        -- ScriptType
        local _ScriptType = {
            ["OnCheckChanged"] = true,
        }
        
        -- FuncProxy
        local _FuncProxy = {
            -- Dispose, release resource
            ["Dispose"] = function(self)
                local id = self.ID
                local _id
                
                if self.Parent.__Childs and type(self.Parent.__Childs) == "table" then
                    for i,v in pairs(self.Parent.__Childs) do
                        if type(v) == "table" then
                            _id = v.ID
                            if _id and type(_id) == "number" and _id > id then
                                _id = _id - 1
                                v.ID = _id
                                v:SetPoint("TOP", self.Parent, "TOP", 0, -(16 + itemHeight * (_id - 1)))
                            end
                        end
                    end
                end
                
                self.Parent.__ItemCount = self.Parent.__ItemCount - 1
                self.Parent.Height = self.Parent.Height - itemHeight
                
                -- Call super's dispose
				self:CallMethod(_Widget[_Base], "Dispose")
            end,
            -- SetText
            ["SetText"] = function(self, text)
                if self.__TextColor then
                    self:GetChild("Text").Text = self.__TextColor..text.."|r"
                else
                    self:GetChild("Text").Text = text
                end
                self.__Text = text
                updateWidth(self.Parent)
            end,
            -- GetText
            ["GetText"] = function(self)
                return self.__Text or ""
            end,
			-- SetDropDownList
			["SetDropDownList"] = function(self, list)
				self.__DropDownList = list
				if self.__DropDownList then
					self:GetChild("ExpandArrow"):Show()
					if list["IsObjectType"] and list:IsObjectType("DropDownList") then
						list.__MenuLevel = self.Parent.__MenuLevel + 1
						list.__MenuBase = self.Parent
					end
				else
					self:GetChild("ExpandArrow"):Hide()
				end
			end,
			-- GetDropDownList
			["GetDropDownList"] = function(self)
				return self.__DropDownList
			end,
			-- SetIcon
			["SetIcon"] = function(self, texture)
				self:GetChild("Icon").Visible = (texture and true) or false
				self:GetChild("Icon"):SetTexture(texture)
			end,
            -- SetTextColor
            ["SetTextColor"] = function(self, r, g, b)
                if r and g and b then
                    self.__TextColor = string.format("|cFF%02x%02x%02x", r, g, b)
                    
                    if self.__Text then
                        self:GetChild("Text").Text = self.__TextColor..self.__Text.."|r"
                    end
                else
                    self.__TextColor = nil
                    self:GetChild("Text").Text = self.__Text
                end
            end,
        }
        
        -- Property
        local _Property = {
			-- DropDownList
            ["DropDownList"] = {
                ["Set"] = function(self, list)
                    self:SetDropDownList(list)
                end,
    
                ["Get"] = function(self)
                    return self:GetDropDownList()
                end,
    
                ["Type"] = _PropertyType.Object,
            },
            -- Text
            ["Text"] = {
                ["Set"] = function(self, text)
                    self:SetText(text)
                end,
                
                ["Get"] = function(self)
                    return self:GetText()
                end,
                
                ["Type"] = _PropertyType.String,
            },
            -- IsCheckButton
            ["IsCheckButton"] = {                
                ["Set"] = function(self, flag)
                    self.__IsCheckButton = (flag and true) or false
                end,
                
                ["Get"] = function(self)
                    return (self.__IsCheckButton and true) or false
                end,
                
                ["Type"] = _PropertyType.Boolean,
            },
            -- Checked
            ["Checked"] = {
                ["Set"] = function(self, flag)
                    self:GetChild("Check").Visible = (flag and true) or false
                    self:Fire("OnCheckChanged")
                end,
                
                ["Get"] = function(self)
                    return self:GetChild("Check").Visible
                end,
                
                ["Type"] = _PropertyType.Boolean,
            },
        }
        
        -- New
        local _New = function(parent)
			local btn = CreateFrame("Button", nil, parent)
            local maxID = parent.__ItemCount or 0
            
            btn.Width = 100
            btn.Height = itemHeight
            
            maxID = maxID + 1
            btn.ID = maxID
            parent.__ItemCount = maxID
            
            -- Anchor
            btn:SetPoint("LEFT", parent, "LEFT", 4, 0)
            btn:SetPoint("RIGHT", parent, "RIGHT", -4, 0)
            btn:SetPoint("TOP", parent, "TOP", 0, - (16 + itemHeight * (maxID - 1)))
            parent.Height = 32 + itemHeight * maxID
            
            -- HighLightTexture
            local highLight = CreateFrame("Texture", "HighLight", btn, "BACKGROUND")
            highLight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
            highLight:SetBlendMode("ADD")
            highLight:SetAllPoints(btn)
            highLight.Visible = false
            
            -- CheckTexture
            local check = CreateFrame("Texture", "Check", btn, "ARTWORK")
            check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
            check.Height = 18
            check.Width = 18
			check.Visible = false
            check:SetPoint("LEFT", btn, "LEFT")
            
            -- IconTexture
            local icon = CreateFrame("Texture", "Icon", btn, "ARTWORK")
            icon.Height = 16
            icon.Width = 16
            icon.Visible = false
            icon:SetPoint("LEFT", btn, "LEFT")     
            
            --[[
            -- ColorSwatch
            local colorsWatch = CreateFrame("Button", "ColorSwatch", btn)
            colorsWatch.Height = 16
            colorsWatch.Width = 16
            colorsWatch.Visible = false
            colorsWatch:SetPoint("RIGHT", btn, "RIGHT", -6, 0)
            colorsWatch:SetNormalTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
            
            local colorBack = CreateFrame("Texture", "Bg", colorsWatch, "BACKGROUND")
            colorBack.Height = 14
            colorBack.Width = 14
            colorBack:SetPoint("CENTER", colorsWatch, "CENTER")
            colorBack:SetVertexColor(1.0, 1.0, 1.0)
            
            colorsWatch.OnClick = colorBack_OnClick
            colorsWatch.OnEnter = colorBack_OnEnter
            colorsWatch.OnLeave = colorBack_OnLeave
            --]]
            
            -- ExpandArrow
            local expandArrow = CreateFrame("Button", "ExpandArrow", btn)
            expandArrow.Height = 16
            expandArrow.Width = 16
            expandArrow.Visible = false
            expandArrow:SetPoint("RIGHT", btn, "RIGHT", 0, 0)
            expandArrow:SetNormalTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
            
            expandArrow.OnClick = expandArrow_OnClick
            expandArrow.OnEnter = expandArrow_OnEnter
            expandArrow.OnLeave = expandArrow_OnLeave
            
            -- FontString
            local text = CreateFrame("FontString","Text",btn,"OVERLAY","GameFontNormal")
            text.JustifyH = "LEFT"
            text:SetPoint("LEFT", btn, "LEFT", 18, 0)
            text:SetHeight(16)
            btn:SetFontString(text)
            
            -- Script
            btn:StackScript("OnEnter", item_OnEnter)
            btn:StackScript("OnLeave", item_OnLeave)
            btn:StackScript("OnClick", OnClick)
            
            --- Font
            btn:SetNormalFontObject(GameFontHighlightSmallLeft)
            btn:SetDisabledFontObject(GameFontDisableSmallLeft)
            btn:SetHighlightFontObject(GameFontHighlightSmallLeft)
            
            return btn
        end
        
        local _WidgetInfo = {
            ["WidgetName"] = _WidgetName,
            ["Base"] = _Base,
            ["FuncProxy"] = _FuncProxy,
            ["Property"] = _Property,
            ["ScriptType"] = _ScriptType,
            ["New"] = _New,
        }
        
        DropDownMenuButton = _GUI.NewWidget(_WidgetInfo)
    end
    
    ------------------------------------------------------
	--------------------- DropDownList ----------------------
	------------------------------------------------------    
	local _WidgetName = "DropDownList"
	local _Base = "Button"
    
    local _DropDownListContainer = CreateFrame("Frame", "IGASGUI_ListContainer")
    _DropDownListContainer.__ShowList = _DropDownListContainer.__ShowList or nil

	-- Script
	local _FrameBackdrop = {
        bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 16,
        insets = { left = 5, right = 5, top = 5, bottom = 5 }
	}
    	
    local function hideDropList(self)
        if self.__Childs and type(self.__Childs) == "table" then
            for i,v in pairs(self.__Childs) do
                if type(v) == "table" and v["IsObjectType"] and v:IsObjectType(DropDownMenuButton) then
                    if v.__DropDownList then
                        hideDropList(v.__DropDownList)
                        v.__DropDownList.Visible = false
                    end
                end
            end
        end
        self.Visible = false
    end
    
	local function OnTimer(self)
        hideDropList(self.Parent)
        self.Interval = 0
	end
	
	local function OnEnter(self)
		self:GetChild("Timer").Interval = 0
        
        if self.__MenuBase then
            self.__MenuBase:Fire("OnEnter")
        end
	end
	
	local function OnLeave(self)
		self:GetChild("Timer").Interval = 2
        if self.__MenuBase then
            self.__MenuBase:Fire("OnLeave")
        end
	end
	
    local function OnShow(self, ...)        
        self:GetChild("Timer").Interval = 2
		
        -- Set the dropdownframe scale
		local uiScale
		local uiParentScale = UIParent:GetScale()
		if ( GetCVar("useUIScale") == "1" ) then
			uiScale = tonumber(GetCVar("uiscale"))
			if ( uiParentScale < uiScale ) then
				uiScale = uiParentScale
			end
		else
			uiScale = uiParentScale
		end
        
		self:SetScale(uiScale)
		
        if self.__MenuLevel > 1 then
            return
        end
        
        if _DropDownListContainer.__ShowList and _DropDownListContainer.__ShowList ~= self then
            _DropDownListContainer.__ShowList.Visible = false
        end
        
        _DropDownListContainer.__ShowList = self

		if self.__ShowOnCursor then
            local cursorX, cursorY = GetCursorPosition()
            cursorX = cursorX/uiScale
            cursorY =  cursorY/uiScale
            
            local offsetX, offsetY
            
            offsetX = cursorX
            offsetY = cursorY
            
            self:ClearAllPoints()
            self:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", offsetX, offsetY)
            
            local x, y = self:GetCenter()
            
            if not (x and y) then
                self:Hide()
                return
            end
            
            -- Determine whether the menu is off the screen or not
            local offscreenY, offscreenX;
            if ( (y - self:GetHeight()/2) < 0 ) then
                offscreenY = 1
            end
            if ( self:GetRight() > GetScreenWidth() ) then
                offscreenX = 1
            end
            
            self:ClearAllPoints()
            if offscreenX and offscreenY then
                self:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMLEFT", offsetX, offsetY)            
            elseif offscreenX then
                self:SetPoint("TOPRIGHT", UIParent, "BOTTOMLEFT", offsetX, offsetY)  
            elseif offscreenY then
                self:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", offsetX, offsetY)  
            end
        end
    end
    
    local function OnHide(self, ...)        
		self:GetChild("Timer").Interval = 0
        
		hideDropList(self)
        
        if self.__MenuLevel > 1 then
            return
        end
        
        if _DropDownListContainer.__ShowList and _DropDownListContainer.__ShowList == self then
            _DropDownListContainer.__ShowList = nil
        end
    end
    
	-- ScriptType
	local _ScriptType = {
	}
	
	--	FuncProxy
	local _FuncProxy = {
        ["AddMenuButton"] = function(self, btnName)
            if not btnName or type(btnName) ~= "string" or btnName == "" then
                error("the parameter must be a string.")
            end
            
            local btn = CreateFrame(DropDownMenuButton, btnName, self)
            btn.Text = btnName
            
            return btn
        end,
        
        ["GetMenuButton"] = function(self, btnName)
            if not btnName or type(btnName) ~= "string" or btnName == "" then
                error("the parameter must be a string.")
            end
            return self:GetChild(btnName)
        end,
        
        ["RemoveMenuButton"] = function(self, btnName)
            if not btnName or type(btnName) ~= "string" or btnName == "" then
                error("the parameter must be a string.")
            end
            if self:GetChild(btnName) then
                self:GetChild(btnName):Dispose()
            end
        end,
	}

	--	Property
	local _Property = {
		["ShowOnCursor"] = {
			["Set"] = function(self, flag)
				self.__ShowOnCursor = (flag and true) or false
			end,
			
			["Get"] = function(self)
				return (self.__ShowOnCursor and true) or false
			end,
			
			["Type"] = _PropertyType.Boolean,
		},
		["MultiSelect"] = {
			["Set"] = function(self, flag)
				self.__MultiSelect = (flag and true) or false
			end,
			
			["Get"] = function(self)
				return (self.__MultiSelect and true) or false
			end,
			
			["Type"] = _PropertyType.Boolean,
		},
	}

	local function _New(parent)
        local frame = CreateFrame("Button", nil, _DropDownListContainer)
        
        -- Remove it make it free to set name
        _DropDownListContainer:RemoveChild(frame)
        
        frame.FrameStrata = "TOOLTIP"
        frame.MouseWheelEnabled = true
        frame.Visible = false
        frame:ClearAllPoints()
        frame:SetBackdrop(_FrameBackdrop)
        frame:SetBackdropBorderColor(1, 1, 1);
		frame:SetBackdropColor(0.09, 0.09, 0.19);
        frame.Height = 8
        frame.Width = 100
		frame.__ShowOnCursor = true
		frame.__MultiSelect = true
        
        frame:StackScript("OnShow", OnShow)
        frame:StackScript("OnHide", OnHide)
        frame:StackScript("OnEnter", OnEnter)
        frame:StackScript("OnLeave", OnLeave)
        
		-- Timer
		local timer = CreateFrame("Timer", "Timer", frame)
		timer.Interval = 0
		timer.OnTimer = OnTimer
        
        -- MenuLevel
        frame.__MenuLevel = 1
        
		return frame
	end

	-- Register
	local _WidgetInfo = {
		["WidgetName"] = _WidgetName,
		["Base"] = _Base,
		["FuncProxy"] = _FuncProxy,
		["Property"] = _Property,
		["ScriptType"] = _ScriptType,
		["New"] = _New,
        ["NotChild"] = true,
	}

	_Widget[_WidgetName] = _GUI.NewWidget(_WidgetInfo)
end
